//==========================================================================
// Copyright (c) 2000-2008, Elastos, Inc. All Rights Reserved.
//==========================================================================
#include <elatypes.h>
#include <ddk.h>
#include <stdlib.h>
#include "usbNetCard.h"

static IDeviceDriver *g_pUSBDev = NULL;
static DzMutex g_usb_send_mutex;
static DzMutex g_usb_recv_mutex;

#define UCDC_INIT           0x0000D001
#define UCDC_STOP           0x0000D002
#define UCDC_WAKE           0x0000D003
#define UCDC_SET_SYNC       0x0000D004
#define UCDC_SET_ASYNC      0x0000D005
#define UCDC_SET_PRIF       0x0000D006
#define UCDC_CLR_BUF        0x0000D007
#define UDCD_WAIT_EVENT     0xA000D001
#define UDCD_SET_EVENT      0xA000D002

#define UVCP_SIGNAL_OUT     0x08001FFF
#define UVCP_RX_CHAR        0x80001000
#define UVCP_ENQ_FAIL       0x80001002

#define CTRL_DISABLECONSOLE  0x0B
#define CTRL_ENABLECONSOLE   0x0C

#define CONTROL_CMD_LEN 36

#define GETMACADDRESS     0x00000005

// MAC address
char cMacAddr[6]={0};


typedef unsigned long   u32_t;
extern "C" void extern_etherifnet_changeIp(wchar_t *ethernetName, void* haddr, u32_t ip, u32_t mask, u32_t gateway, u32_t priDns, u32_t secdDns);
extern void lwipentry();
extern void eth_init(wchar_t *ethernetName);
extern int eth_deinit(wchar_t *ethernetName);


void USBNetCard::Dispose()
{
}

ECode USBNetCard::Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent)
{

    WaitResult wr;
    ECode ec;
    //kprintf("in USBNetCard::Read \n");
    g_usb_recv_mutex.Lock(&wr);
    pBuffer->SetUsed(0);
    ec = g_pUSBDev->Read(0, bytesToRead, pBuffer, NULL);
    if (FAILED(ec)) {
        kprintf("Cann't get Usb data \n");
        g_usb_recv_mutex.Unlock();
        return ec;
    }
    if (CONTROL_CMD_LEN == pBuffer->GetUsed()) {
        BYTE* buffer = (BYTE*)pBuffer->GetPayload();
        UInt32* prefix = (UInt32*)buffer;
        if(0x12345678 !=*prefix || 0x12345678 !=*(prefix + 1)) return NOERROR;
        Int16* cmd = (Int16*)(buffer + 8);

        // 1 initial
        switch (*cmd) {
            case 1:
                kprintf("change ip\n");
                memcpy(cMacAddr,buffer + 10,6);
                extern_etherifnet_changeIp(L"usbnetcard", buffer + 10,*(u32_t*)(buffer + 16),
                        *(u32_t*)(buffer + 20), *(u32_t*)(buffer + 24), *(u32_t*)(buffer + 28),0);
                sendAddressConfirm();
                break;
            default:break;
        }
        pBuffer->SetUsed(0);
    }
   g_usb_recv_mutex.Unlock();
   //kprintf("in USBNetCard::Read end\n");
    return NOERROR;
}

ECode USBNetCard::Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf & buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    WaitResult wr;
    int nSendSize = 0;
    //kprintf("USBNetCard::Write-begin to write\n");
    g_usb_send_mutex.Lock(&wr);
    ECode ec = g_pUSBDev->Write(0, buffer, &nSendSize, NULL);
    g_usb_send_mutex.Unlock();
    //kprintf("USBNetCard::Write-end write\n");
    if (FAILED(ec)) {
        kprintf("Write Usb Failed\n");
        return -1;
    }

    if (NULL != pBytesWritten) {
        *pBytesWritten = nSendSize;
    }

    return NOERROR;
}

ELAPI _CProfile_GetAString(AString appName, AString keyName,
        AStringBuf *pReturnedString);

Int32 USBNetInitPort()
{
    kprintf("in USBNet InitPort!\n");
    AStringBuf_<17> mac;
    ECode ec;
    if(!*(Int32* )cMacAddr){
        ec = _CProfile_GetAString("Tcpip", "MacAddress", &mac);
        if (ec != NOERROR) {
            cMacAddr[0] = 0x00;
            cMacAddr[1] = 0x02;
            cMacAddr[2] = 0x03;
            cMacAddr[3] = 0x00;
            cMacAddr[4] = 0x02;
            cMacAddr[5] = 0x03;
        }
        else {
            char* temp_pointer = (char*)mac;
            cMacAddr[0] = (((temp_pointer[0]-'0')&0x0f) << 4)
                            + ((temp_pointer[1]-'0')&0x0f);
            cMacAddr[1] = (((temp_pointer[3]-'0')&0x0f) << 4)
                            + ((temp_pointer[4]-'0')&0x0f);
            cMacAddr[2] = (((temp_pointer[6]-'0')&0x0f) << 4)
                        + ((temp_pointer[7]-'0')&0x0f);
            cMacAddr[3] = (((temp_pointer[9]-'0')&0x0f) << 4)
                        + ((temp_pointer[10]-'0')&0x0f);
            cMacAddr[4] = (((temp_pointer[12]-'0')&0x0f) << 4)
                        + ((temp_pointer[13]-'0')&0x0f);
            cMacAddr[5] = (((temp_pointer[15]-'0')&0x0f) << 4)
                        + ((temp_pointer[16]-'0')&0x0f);
        }
    }
    MemoryBuf_<1> memBuf;
    ec = DzFindService(L"device:usbserfornet", (IInterface **)&(g_pUSBDev));// usbser
    if (FAILED(ec)) {
        kprintf("Cann't find device:usbserfornet service!\n");
        return -1;
    }

    ec = g_pUSBDev->Control(UCDC_STOP, memBuf, NULL, NULL);
    if (FAILED(ec)) {
        kprintf("Cann't Stop UDC Transmit!\n");
        return -1;
    }

    ec = g_pUSBDev->Control(UCDC_CLR_BUF, memBuf, NULL, NULL);
    if (FAILED(ec)) {
        kprintf("Cann't clear UDC buffer!\n");
        return -1;
    }

    ec = g_pUSBDev->Control(UCDC_SET_SYNC, memBuf, NULL, NULL);
    if (FAILED(ec)) {
        kprintf("Cann't set to synchronous!\n");
        return -1;
    }

    ec = g_pUSBDev->Control(UCDC_WAKE, memBuf, NULL, NULL);
    if (FAILED(ec)) {
        kprintf("Cann't Wake UDC Transmit!\n");
        return -1;
    }

    return 1;
}

ECode USBNetCard::getAddressByUSB()
{
    kprintf("in USBNetCard::getAddressByUSB\n");
    BYTE getAddressCmd[CONTROL_CMD_LEN] =
        {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x00, 0x01};
    MemoryBuf ebbOutData(getAddressCmd, CONTROL_CMD_LEN);
    return Write(0, ebbOutData, NULL, NULL);
}

ECode USBNetCard::sendAddressConfirm()
{
    kprintf("in USBNetCard::sendAddressConfirm\n");
    BYTE addressConfirmCmd[CONTROL_CMD_LEN] =
        {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x00, 0x02};
    MemoryBuf ebbOutData(addressConfirmCmd, CONTROL_CMD_LEN);
    return Write(0, ebbOutData, NULL, NULL);
}

ECode USBNetCard::Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf & inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent ** ppCompletionEvent)
{
    // printf("NetCard::Control,  code is %d\n", nControlCode);
    if (nControlCode == DRVINITALIZE) {
        // Init virtual network driver
        kprintf("start netcard driver\n");
        if (pOutBuffer != NULL) {
            pOutBuffer->Copy((Byte*)cMacAddr, 6);
        }
        if(m_hasStarted) return NOERROR;
        if (!USBNetInitPort()) {
            return E_INVALID_OPERATION;
        }
        m_hasStarted=true;
        lwipentry();
        eth_init(L"usbnetcard");
        // ec = getAddressByUSB();
        //if(FAILED(ec)) return ec;
    }
    else if (nControlCode == DRVSHUTDOWN) {
        kprintf("stop netcard driver\n");
        if(!m_hasStarted) return NOERROR;
        eth_deinit(L"usbnetcard");
        g_pUSBDev->Control(UCDC_STOP, NULL_MEMORYBUF, NULL, NULL);
        m_hasStarted=false;
    }
    else if (nControlCode == GETMACADDRESS) {
        // return the MAC address
        if (pOutBuffer == NULL) {
            return E_INVALID_ARGUMENT;
        }
        pOutBuffer->Copy((Byte*)cMacAddr, 6);
    }
    else {
        kprintf("USBNetCard unknown ControlCode %d\n", nControlCode);
    }
    return NOERROR;
}

USBNetCard::USBNetCard()
{
    m_hasStarted=false;
}

IDeviceDriver *pUSBNetDriver;

IDeviceDriver * CDECL CreateUSBNetCard(uint_t uDeviceNo, void *pvParameter)
{
    pUSBNetDriver = new USBNetCard();
    if (NULL == pUSBNetDriver) {
        return NULL;
    }
    pUSBNetDriver->AddRef();
    return pUSBNetDriver;
}
